package com.ruoyi.system.service.impl;

import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ZipUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;

import com.ruoyi.system.domain.AnalysisNMFReq;
import com.ruoyi.system.domain.AnalysisReq;
import com.ruoyi.system.service.IRadapterService;

import lombok.extern.slf4j.Slf4j;
import org.rosuda.JRI.REXP;
import org.rosuda.JRI.Rengine;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
public class RadapterServiceImpl implements IRadapterService {
    @Value("${dataFilePath}")
    private String dataFilePath;
    @Value("${resultFilePath}")
    private String resultFilePath;
    @Value("${sumResultFilePath}")
    private String sumResultFilePath;
    @Value("${zipResultFilePath}")
    private String zipResultFilePath;
    @Value("${resultFileCount}")
    private String countFilePath;
    public List<String> list(){
        return getFiles(dataFilePath);
    }
    public List<Map<String,Object>> targetFiles(){
        return getFileObjs(dataFilePath);
    }
    public void upload(MultipartFile[] files) throws IOException {
        for (MultipartFile file : files) {
            if (file.isEmpty()) {
                continue;
            }
            FileUploadUtils.upload(dataFilePath,file);
        }
    }
    /**
     * 工作目录必需先创建好，系统不会自动创建目录
     * 目前没有办法捕捉R的错误信息，如果函数ConsensusClusterPlusAnalysis，NMFAnalysis返回了null,基本上就是发生错误了
     * 建议先写R脚本调试，没问题后再用JRI写一遍
     * 工作目录中要创建sum data目录，否则输出的文件会很少，因为Themis_custom_method等三个方法没有执行
     * path的路径必需在工作目录里面
     * 不要在函数参数中使用赋值语句，（如 NMFAnalysis(expFile,geneFile,directory,clusterNum = clusterNum,method = method,nrun = nrun,seed = seed)）会出错，不会收到返回值。
     * 应该写成下面形式 NMFAnalysis(expFile,geneFile,directory,clusterNum,method,nrun,seed)
     */
    public void analysis(AnalysisReq param){
        String expFiles = param.getExpFiles();//测试一下能不能传回车
        String geneFile = param.getGene();
        //Rengine engine = new Rengine(null, false, null);
        Rengine engine = Rengine.getMainEngine();
        if (!engine.waitForR()) {
            log.info("Cannot load R");
            return;
        }
        engine.eval("library(Themis2)");
        engine.eval("library(ConsensusClusterPlus)");
        engine.assign("expFile", dataFilePath+expFiles);
        engine.assign("geneFile", geneFile);
        engine.assign("directory", resultFilePath);
        engine.assign("path", sumResultFilePath);
        
        engine.assign("maxKParam", String.valueOf(param.getMaxK()));
        engine.assign("repsParam", String.valueOf(param.getReps()));
        engine.assign("pItemParam", String.valueOf(param.getPItem()));
        engine.assign("clusterNumParam", String.valueOf(param.getClusterNum()));
        engine.assign("clusterAlgParam", param.getClusterAlg());
        engine.assign("distanceParam", param.getDistance());
        engine.assign("pFeatureParam", String.valueOf(param.getPFeature()));
        engine.assign("seedParam", String.valueOf(param.getSeed()));
        engine.assign("plotParam", param.getPlot());
        
        engine.eval("max <- maxKParam");
        engine.eval("reps <- repsParam");
        engine.eval("pItem <- pItemParam");
        engine.eval("clusterNum <- clusterNumParam");
        engine.eval("clusterAlg <- clusterAlgParam");
        engine.eval("distance <- distanceParam");
        engine.eval("pFeature <- pFeatureParam");
        engine.eval("seed <- seedParam");
        engine.eval("plot <- plotParam");
        
        engine.eval("exp <- expFile");
        engine.eval("gene <- geneFile");
        engine.eval("dir <- directory");
        engine.eval("p <- path");
        
        engine.eval("setwd(dir)");
        
        REXP dir = engine.eval("print(dir)");
        REXP gene = engine.eval("print(gene)");
        REXP exp = engine.eval("print(exp)");
        REXP p = engine.eval("print(p)");
        
        REXP a = engine.eval("print(max)");
        REXP e = engine.eval("print(reps)");
        REXP m = engine.eval("print(pItem)");
        REXP n = engine.eval("print(clusterNum)");
        REXP c = engine.eval("print(clusterAlg)");
        REXP d = engine.eval("print(distance)");
        REXP f = engine.eval("print(pFeature)");
        REXP s = engine.eval("print(seed)");
        REXP o = engine.eval("print(plot)");
        
        
        log.info("eval :: print param dir="+dir);
        log.info("eval :: print param gene="+gene);
        log.info("eval :: print param exp="+exp);
        log.info("eval :: print param p="+p);
        
        log.info("eval :: print param max="+a);
        log.info("eval :: print param reps="+e);
        log.info("eval :: print param pItem="+m);
        log.info("eval :: print param clusterNum="+n);
        log.info("eval :: print param clusterAlg="+c);
        log.info("eval :: print param distance="+d);
        log.info("eval :: print param pFeature="+f);
        log.info("eval :: print param seed="+s);
        log.info("eval :: print param plot="+o);
        
        /*log.info("call function ConsensusClusterPlusAnalysis,start.....");
        REXP cr = engine.eval("ConsensusClusterPlusAnalysis(exp, gene, dir,maxK = 9, reps = 1000, pItem = 0.8,clusterNum = 2,clusterAlg = \"km\", distance = \"pearson\", pFeature = 1,seed = 123456, plot = \"png\")");
        log.info("call function ConsensusClusterPlusAnalysis,end.....");
        log.info("call function ConsensusClusterPlusAnalysis,return value = "+cr);
        log.info("call function NMFAnalysis,start.....");
        engine.eval("Themis_custom_method(dir, p)");
        engine.eval("Themis_process(dir)");
        engine.eval("Themis_output(dir)");
        log.info("R program end...");*/
        engine.end();
    }
    public void analysisNMF(AnalysisNMFReq param){
        String expFile = param.getExpFiles();
        String geneFile = param.getGene();
        Rengine engine = new Rengine(null, false, null);
        //Rengine engine = Rengine.getMainEngine();//空指针
        if (!engine.waitForR()) {
            log.info("Cannot load R");
            return;
        }
        engine.eval("library(Themis2)");
        engine.eval("library(NMF)");
        engine.assign("expFile", expFile);
        engine.assign("geneFile", geneFile);
        engine.assign("directory", resultFilePath);
        engine.assign("path", sumResultFilePath);
        
        engine.assign("methodParam", param.getMethod());
        engine.assign("nrunParam", String.valueOf(param.getNrun()));
        engine.assign("seedParam", String.valueOf(param.getSeed()));
        engine.assign("clusterNumParam", String.valueOf(param.getClusterNum()));
        
        engine.eval("exp <- expFile");
        engine.eval("gene <- geneFile");
        engine.eval("dir <- directory");
        engine.eval("p <- path");
        
        engine.eval("methodVal <- methodParam");
        engine.eval("nrunVal <- nrunParam");
        engine.eval("seedVal <- seedParam");
        engine.eval("clusterNumVal <- clusterNumParam");
        
        engine.eval("setwd(dir)");
        
        REXP dir = engine.eval("print(dir)");
        REXP gene = engine.eval("print(gene)");
        REXP exp = engine.eval("print(exp)");
        REXP p = engine.eval("print(p)");
        
        REXP m = engine.eval("print(methodVal)");
        REXP u = engine.eval("print(nrunVal)");
        REXP e = engine.eval("print(seedVal)");
        REXP c = engine.eval("print(clusterNumVal)");
        
        log.info("eval :: print param dir="+dir);
        log.info("eval :: print param gene="+gene);
        log.info("eval :: print param exp="+exp);
        log.info("eval :: print param p="+p);
        
        log.info("eval :: print param method="+m);
        log.info("eval :: print param nrun="+u);
        log.info("eval :: print param seed="+e);
        log.info("eval :: print param clusterNum="+c);
        
        log.info("call function NMFAnalysis,start.....");
        //REXP nr = engine.eval("val <- (exp,gene,dir,clusterNum = 2,method = \"brunet\",nrun = 10,seed = 123456)");//生成了一堆文件
        REXP nr = engine.eval("val <- NMFAnalysis(exp,gene,dir,clusterNum = 2,method = \"brunet\",nrun = 10,seed = 123456)");//生成了一堆文件

        log.info("call function NMFAnalysis,end.....");
        log.info("call function NMFAnalysis,return value = "+nr);
        engine.eval("Themis_custom_method(dir, p)");
        engine.eval("Themis_process(dir)");
        engine.eval("Themis_output(dir)");

        REXP nmfReturn = engine.eval("print(val$num_files)");
        Double rFileNums = nmfReturn.asDouble();

        log.info("NMFAnalysis retrun ="+nmfReturn);
        log.info("NMFAnalysis retrun rFileNums ="+rFileNums);


        log.info("R program end...");
        engine.end();
        //怎样取得R函数的返回值，如果有多个

        if(rFileNums!=null){
            saveCount(rFileNums.intValue());
        }

    }
    public void toZip() {
        File dir = new File(resultFilePath);
        //压缩后zip包文件路径
        String zipName = "zip_"+System.currentTimeMillis()+".zip";
        File dest = new File(zipResultFilePath+zipName);
        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(dest);
            ZipUtils.zip(dir, outputStream);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private void saveCount(Integer num){
        Integer writeNum = num==null?0:num;
        File countFile = new File(countFilePath);
        if (countFile.exists()){
            // 文件存在，删除文件
            countFile.delete();
        }else{
            // 文件不存在，创建文件
            try {
                boolean created = countFile.createNewFile();
                if (created) {
                    FileWriter writer = new FileWriter(countFile);
                    writer.write(writeNum+"\n");
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void del(List<String> files,int type){
        if(type==0){
            delFiles(files,dataFilePath);
        }else {
            delFiles(files,resultFilePath);
        }
    }

    public void delAll(String path){
            File dir = new File(path);
            if (dir.exists()) {
                if (dir.isDirectory()) {
                    File[] files = dir.listFiles();
                    for (File f : files) {
                        if (f.isFile()) {
                            f.delete();
                        } else if (f.isDirectory()) {
                            delAll(f.getAbsolutePath());
                        }
                    }
                    dir.delete();
                } else {
                    dir.delete();
                }
            }
    }


    private void delFiles(List<String> files,String path){
        for(String n:files){
            File file = new File(path+"/"+n);
            file.delete();
        }
    }

    public List<String> show(){
        return getFiles(resultFilePath);
    }
    public void delete(List<String> filePaths){
        for(String path:filePaths){
            File dir = new File(path);
            dir.delete();
        }
    }
    private List<String> getFiles(String name){
        List<String> resule = new ArrayList<>();
        File dir = new File(name);
        File[] files = dir.listFiles();
        if(files!=null){
            resule = Arrays.stream(files).map(f->f.getName()).collect(Collectors.toList());
        }
        return resule;
    }
    private List<Map<String,Object>> getFileObjs(String name){
        List<Map<String,Object>> resule = new ArrayList<>();
        File dir = new File(dataFilePath);
        File[] files = dir.listFiles();
        if(files!=null){
            resule = Arrays.stream(files).map(f->{
                Map<String,Object> row = new HashMap<>();
                row.put("name",f.getName());
                //row.put("absolutePath",f.getAbsolutePath());
                row.put("path",f.getPath());
                return row;
            }).collect(Collectors.toList());
        }
        return resule;
    }
    public File getLastModifiedFile(){
        File dir = new File(zipResultFilePath);
        File[] files = dir.listFiles();
        List<File> result = new ArrayList<>();

        if(files!=null){
            result = Arrays.stream(files).filter( f->{
                String fname = f.getName();
                String extName = StringUtils.substring(fname,fname.lastIndexOf("."));
                        return extName.equals(".zip")?true:false;
                    }).sorted(Comparator.comparing(file->file.getName()))
                    .collect(Collectors.toList());
        }
        if(result.size()>0){
            return result.get(result.size()-1);
        }
        return null;

    }

    public Boolean isFileAllBuilding(){
        Integer count = 0;
        File finishFile = new File(countFilePath);
        File dir = new File(resultFilePath);
        File[] files = dir.listFiles();
        try {
            BufferedReader reader = new BufferedReader(new FileReader(finishFile));
            String line;
            while ((line = reader.readLine()) != null) {
                count = Integer.valueOf(line);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return files.length>=count?true:false;
    }

    public static void main( String[] args ){
        //System.out.println( "call R themis!" );
        String geneFile = "D:\\Rworks\\demo\\gene.txt";
        String expFile = "D:\\Rworks\\demo\\data\\ACC_norm.txt";
        String directory = "D:\\Rworks\\demo\\result";
        String path = "D:\\Rworks\\demo\\result\\sum data";
        themis(expFile,geneFile,directory,path);
        //themis();
        //callFunction();
        /*String hc = "ACC\nBCC\nDCC\nECC\n";
        System.out.println(hc);*/
    }
    /**
     * 工作目录必需先创建好，系统不会自动创建目录
     * 目前没有办法捕捉R的错误信息，如果函数ConsensusClusterPlusAnalysis，NMFAnalysis返回了null,基本上就是发生错误了
     * 建议先写R脚本调试，没问题后再用JRI写一遍
     * 工作目录中要创建sum data目录，否则输出的文件会很少，因为Themis_custom_method等三个方法没有执行
     * path的路径必需在工作目录里面
     */
    public static void themis(String expFile,String geneFile,String directory,String path){
        Rengine engine = new Rengine(null, false, null);
        if (!engine.waitForR()) {
            System.out.println("Cannot load R");
            return;
        }
        engine.eval("library(Themis2)");
        engine.eval("library(ConsensusClusterPlus)");
        engine.eval("library(NMF)");
        engine.assign("expFile", expFile);
        engine.assign("geneFile", geneFile);
        engine.assign("directory", directory);
        engine.assign("path", path);
        engine.eval("exp <- expFile");
        engine.eval("gene <- geneFile");
        engine.eval("dir <- directory");
        engine.eval("p <- path");
        engine.eval("setwd(dir)");
        REXP dir = engine.eval("print(dir)");
        REXP gene = engine.eval("print(gene)");
        REXP exp = engine.eval("print(exp)");
        REXP p = engine.eval("print(p)");
        System.out.println("eval :: print param dir="+dir);
        System.out.println("eval :: print param gene="+gene);
        System.out.println("eval :: print param exp="+exp);
        System.out.println("eval :: print param p="+p);
        System.out.println("call function ConsensusClusterPlusAnalysis,start.....");
        REXP cr = engine.eval("ConsensusClusterPlusAnalysis(exp, gene, dir,maxK = 9, reps = 1000, pItem = 0.8,clusterNum = 2,clusterAlg = \"km\", distance = \"pearson\", pFeature = 1,seed = 123456, plot = \"png\")");
        System.out.println("call function ConsensusClusterPlusAnalysis,end.....");
        System.out.println("call function ConsensusClusterPlusAnalysis,return value = "+cr);
        System.out.println("call function NMFAnalysis,start.....");
        REXP nr = engine.eval("NMFAnalysis(exp,gene,dir,clusterNum = 2,method = \"brunet\",nrun = 10,seed = 123456)");
        System.out.println("call function NMFAnalysis,end.....");
        System.out.println("call function NMFAnalysis,return value = "+nr);
        engine.eval("Themis_custom_method(dir, p)");
        engine.eval("Themis_process(dir)");
        engine.eval("Themis_output(dir)");
        System.out.println("R program end...");
        engine.end();
    }


}
